/*
 * utilesConexion.c
 *
 *  Created on: 29/11/2011
 *      Author: utn_so
 */


#include<stdio.h>
#include<stdint.h>
#include<stdlib.h>
#include <string.h>
#include <sys/select.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <pthread.h>
#include "./includes/utilesConexion.h"
#include "../../Commons/src/includes/nipc.h"
#include "includes/variablesGlobales.h"

void agregarPedido (ptrNodoPedido *ColaFte,ptrNodoPedido *ColaFin,nodo_pedido valores){
	ptrNodoPedido ptrNuevo;
	ptrNuevo=malloc(sizeof(nodo_pedido));

	ptrNuevo->peticion=valores.peticion;
	ptrNuevo->flagRW=valores.flagRW;
	ptrNuevo->lonMsj=valores.lonMsj;
	memcpy(&ptrNuevo->mensaje,valores.mensaje,valores.lonMsj);
	ptrNuevo->ptrSgte=NULL;

	if(*ColaFte==NULL) {
		*ColaFte=ptrNuevo;
	}
	else{
		(*ColaFin)->ptrSgte=ptrNuevo;
	}
	*ColaFin=ptrNuevo;
}

uint32_t suprimirPedido (ptrNodoPedido *ColaFte, ptrNodoPedido *ColaFin){
	ptrNodoPedido ptr;
	uint32_t sector;
	ptr=*ColaFte;
	*ColaFte=(*ColaFte)->ptrSgte;
	if (*ColaFte==NULL){
		*ColaFin=NULL;
	}
	sector = ptr->peticion;
	free(ptr);
	return sector;
}

void pedirLectura(uint32_t socket, uint32_t numSector, char buf[512])
{
paqueteNIPC *paqueteP;
paqueteNIPC paquete;
payloadEscritura_t payloadEscritura;

paqueteP = malloc(sizeof(paqueteNIPC));

	paqueteP->num_msg = 1;
	paqueteP->longitud = sizeof(uint32_t);

	memcpy(&paqueteP->payload,&numSector, sizeof(uint32_t));

	if(send(socket,paqueteP,sizeof(paqueteNIPC),0)==-1){
		perror("send");
	} else {
		puts("Se envió del PFS");
		if(recv(socket,&paquete,sizeof(paqueteNIPC),0)==-1){
			perror("recv");
		} else {
			puts("Se recibió el paquete");
			if(paquete.num_msg == 2){
				puts("Se leyó");
				memcpy(&payloadEscritura,paquete.payload, sizeof(paquete.payload));
				memcpy(buf,&payloadEscritura.contenido,sizeof(payloadEscritura.contenido));
			};
		};
	};

	free(paqueteP);
}

void pedirEscritura(uint32_t socket, uint32_t numSector, char buf[512]){
paqueteNIPC *paqueteP;
paqueteNIPC paquete;
payloadEscritura_t payloadEscritura;

paqueteP = malloc(sizeof(paqueteNIPC));

	paqueteP->num_msg = 3;
	paqueteP->longitud = 512 + sizeof(uint32_t);

	memcpy(&payloadEscritura.sector,&numSector, sizeof(uint32_t));

	memcpy(&payloadEscritura.contenido, buf, sizeof(payloadEscritura.contenido));

	memcpy(&paqueteP->payload, &payloadEscritura, sizeof(paquete.payload));

	if(send(socket,paqueteP,sizeof(paqueteNIPC),0)==-1){
		perror("send");
	} else {
		puts("Se envió del PFS");
		if(recv(socket,&paquete,sizeof(paqueteNIPC),0)==-1){
			perror("recv");
		} else {
			puts("Se recibió el paquete");
			if(paquete.num_msg == 4){
				puts("Se escribió");
				memcpy(&payloadEscritura,paquete.payload,sizeof(paquete.payload));
				if(numSector==payloadEscritura.sector){
				strcpy(buf,"ok");
				};
			};
		};
	};
	free(paqueteP);
}
//
//void tomarPedido(parametros *parametros){
//	char buf[516];
//	paqueteNIPC paquete;
//	paqueteNIPC *paqueteP;
//	nodo_data valores;
//	payloadEscritura_t payloadEscritura;
//	uint32_t sector;
//	nodo_pedido prueba;
//
//	paqueteP = malloc(sizeof(paqueteNIPC));
//
//			while(1){
//				if(noHayPeticiones(parametros->colaFte)){
//					//                      printf("La cola esta vacía");
//				} else {
//					if(parametros->colaFte->flagRW == 0){ //Es Lectura
//						paqueteP->num_msg = 1;
//						paqueteP->longitud = sizeof(uint32_t);
//
//						memcpy(&sector, &parametros->colaFte->peticion, sizeof(sector));
//
//						memcpy(&paqueteP->payload,&sector, sizeof(buf));
//
//						if(send(parametros->socket,paqueteP,sizeof(paqueteNIPC),0)==-1){
//							perror("send");
//						} else {
//							puts("Se envió del PFS al RAID");
//							if(recv(parametros->socket,&paquete,sizeof(paqueteNIPC),0)==-1){
//								perror("recv");
//							} else {
//								puts("Se recibió el paquete del RAID");
//								if(paquete.num_msg == 2){
//									//                                                      memcpy(&valores.mensaje, paquete.payload, 512);
//									//                                                      valores.lonMsj = paquete.longitud;
//									//                                                      agregarData(&parametros->colaFteD,&parametros->colaFinD, valores);
//									suprimirPedido(&parametros->colaFte,&parametros->colaFin);
//									//                                                      agregarData(&parametros->colaFteD,&parametros->colaFinD, valores);
//									puts("Se leyó");
//									printf("%s",paquete.payload);
//								};
//							};
//						};
//					} else {
//						if(parametros->colaFte->flagRW == 1){ //Es Escritura
//							paqueteP->num_msg = 3;
//							paqueteP->longitud = parametros->colaFte->lonMsj + sizeof(uint32_t);
//
//							memcpy(&sector, &parametros->colaFte->peticion, sizeof(sector));
//
//							memcpy(&payloadEscritura.sector,&sector, sizeof(uint32_t));
//
//							memcpy(&payloadEscritura.contenido, &parametros->colaFte->mensaje, sizeof(payloadEscritura.contenido));
//
//							memcpy(&paqueteP->payload, &payloadEscritura, sizeof(paquete.payload));
//
//							if(send(parametros->socket,paqueteP,sizeof(paqueteNIPC),0)==-1){
//								perror("send");
//							} else {
//								puts("Se envió del PFS al RAID");
//								if(recv(parametros->socket,&paquete,sizeof(paqueteNIPC),0)==-1){
//									perror("recv");
//								} else {
//									puts("Se recibió el paquete del RAID");
//									if(paquete.num_msg == 4){
//										prueba.flagRW = 1;
//										prueba.lonMsj = 0;
//										memcpy(&payloadEscritura, paquete.payload, sizeof(payloadEscritura));
//										memcpy(&prueba.mensaje,&payloadEscritura.contenido, sizeof(prueba.mensaje));
//										memcpy(&prueba.peticion,&payloadEscritura.sector, sizeof(uint32_t));
//										agregarPedido(&parametros->colaFteD,&parametros->colaFinD, prueba);
//										suprimirPedido(&parametros->colaFte,&parametros->colaFin);
//										puts("Se escribió");
//										printf("%s",paquete.payload);
//									};
//								};
//							};
//						};
//					}
//				}
//			}
//}

void agregarData (ptrNodoData *ColaFte,ptrNodoData *ColaFin,nodo_data valores){
	ptrNodoData ptrNuevo;
	ptrNuevo=malloc(sizeof(nodo_data));

	ptrNuevo->lonMsj=valores.lonMsj;
	memcpy(&ptrNuevo->mensaje,valores.mensaje,516);
	ptrNuevo->ptrSgte=NULL;

	if(*ColaFte==NULL) {
		*ColaFte=ptrNuevo;
	}
	else{
		(*ColaFin)->ptrSgte=ptrNuevo;
	}
	*ColaFin=ptrNuevo;
}

uint32_t suprimirData(ptrNodoData *ColaFte, ptrNodoData *ColaFin){
	ptrNodoData ptr;
	ptr=*ColaFte;
	*ColaFte=(*ColaFte)->ptrSgte;
	if (*ColaFte==NULL){
		*ColaFin=NULL;
	}
	return 0;
}

uint32_t noHayPeticiones (ptrNodoPedido ColaFte){
	if(ColaFte == NULL){ // si la lista esta vacia
		return 1;   //returna verdadero
	}
	else{
		return 0;   // returna falso
	}
}

void mostrarListaPedidos (ptrNodoPedido ColaFte){
	ptrNodoPedido ptr;
	ptr=ColaFte;
	if (ptr == NULL){
		printf("La cola esta vacia.\n\n");
	}
	else{
		printf("La cola es: \n");
		while(ptr !=NULL){
			printf("%d --> ", ptr->peticion);
			ptr=ptr->ptrSgte;
		}
		printf("NULL\n\n");
	}
}

void mostrarListaDatos (ptrNodoData ColaFte){
	ptrNodoData ptr;
	ptr=ColaFte;
	if (ptr == NULL){
		printf("La cola esta vacia.\n\n");
	}
	else{
		printf("La cola es: \n");
		while(ptr !=NULL){
			printf("%s --> ", ptr->mensaje);
			ptr=ptr->ptrSgte;
		}
		printf("NULL\n\n");
	}
}

uint8_t* pedirLecturaCluster(uint32_t primerSector){
		paqueteNIPC *paqueteP;
		paqueteNIPC paquete;
		uint32_t n,m;
		payloadEscritura_t payloadEscritura;
		clusterRec_t cluster[8];
		uint8_t returna[4096];

		paqueteP=malloc(sizeof(paqueteNIPC));

		/* Creo el Socket: SOCK_STREAM para TCP y SOCK_DGRAM par UDP */
		 int descriptor = socket(AF_INET, SOCK_STREAM, 0);

		/* Direccion Local */
		struct sockaddr_in *local_address = malloc(sizeof(struct sockaddr_in));
		/* Direccion remota ( a la que me quiero conectar )*/
		struct sockaddr_in *remote_address = malloc(sizeof(struct sockaddr_in));
		/* Direccion remota ( a la que me quiero conectar )*/
		struct sockaddr_in *remote_addressPDD = malloc(sizeof(struct sockaddr_in));

		{       /* Con esto fuerzo a que el puerto local sea el 5201 y que tome la IP por defecto de la PC */
			local_address->sin_family = AF_INET;
			local_address->sin_addr.s_addr = INADDR_ANY;
			local_address->sin_port = htons(5302);

			bind(descriptor, (struct sockaddr *)local_address, sizeof(struct sockaddr_in));
		}

		{       /* Con esto indico que me quiero conectar al puerto 9034 de la IP 127.0.0.1 (localhost)-->RAID */
			remote_address->sin_family = AF_INET;
			remote_address->sin_addr.s_addr = inet_addr("127.0.0.1");
			remote_address->sin_port = htons(9065);
		}

		{       /* Con esto indico que me quiero conectar al puerto 9048 de la IP 127.0.0.1 (localhost) -> PDD*/
			remote_addressPDD->sin_family = AF_INET;
			remote_addressPDD->sin_addr.s_addr = inet_addr("127.0.0.1");
			remote_addressPDD->sin_port = htons(5360);
		}

		/* Me conecto al servidor */
		if(connect(descriptor, (struct sockaddr *)remote_address , sizeof(struct sockaddr_in))==-1){
			//perror("connect");
			puts("No se pudo conectar al RAID");
			if(connect(descriptor, (struct sockaddr *)remote_addressPDD, sizeof(struct sockaddr_in))==-1){
				perror("connect");
				puts("No se pudo conectar al PDD");
			};
		};

		paqueteP->num_msg = 0;
		paqueteP->longitud = 0;

		if(send(descriptor, paqueteP, sizeof(paqueteNIPC), 0)==-1){
			perror("send");
			puts("Falló el envío del paquete para HS");
		};

		if(recv(descriptor, &paquete, sizeof(paqueteNIPC), 0)==-1){
			perror("recv");
			puts("No se pudo recibir la respuesta del intento de Handshake");
		};

		if((paquete.num_msg==0)&&(paquete.longitud==0)){
			puts("Handshake exitoso");

			//puts("Acá empieza");
	//---------------------------------------- Aca va el main del pfs--------------------------------------
		//	sector = 0;

			//Leer un cluster desde ese sector

			for(n=0;n<8;n++){
				paqueteP->num_msg = 1;
				paqueteP->longitud = sizeof(uint32_t);
				memcpy(&paqueteP->payload,&primerSector,sizeof(uint32_t));

				if(send(descriptor,paqueteP,sizeof(paqueteNIPC),0)==-1){
					perror("send");
				};
				cluster[n].numSector = primerSector;
				primerSector++;
			};

			for(n=0;n<8;n++){

				if(recv(descriptor,&paquete,sizeof(paqueteNIPC),0)==-1){
							perror("recv");
				};

				if(paquete.num_msg == 2){

				memcpy(&payloadEscritura, paquete.payload, sizeof(payloadEscritura));

				m = 0;

				while(cluster[m].numSector!=payloadEscritura.sector){
					m++;
				};

				memcpy(&cluster[m].contenido,payloadEscritura.contenido,sizeof(payloadEscritura.contenido));

				};

			};

			for(n=0;n<8;n++){
				memcpy(returna+(512*n),&cluster[n].contenido,512);
			};


	//-------------------------------------------------------------------------------------------------------


		} else {
			if(paquete.num_msg==-1){
				printf("%s\n",paquete.payload);
			};
			puts("Handshake falló");
		};


		/* Cierro el socket y por ende la conexion */
		free(paqueteP);
		close(descriptor);

		free(local_address);
		free(remote_address);
		free(remote_addressPDD);
		usleep(100000);
		return returna;
	}

void pedirEscrituraCluster(uint32_t primerSector, uint8_t *contCluster){
		paqueteNIPC *paqueteP;
		paqueteNIPC paquete;
		uint32_t n,m;
		payloadEscritura_t payloadEscritura;
		clusterRec_t cluster[8];

		paqueteP=malloc(sizeof(paqueteNIPC));

		/* Creo el Socket: SOCK_STREAM para TCP y SOCK_DGRAM par UDP */
		 int descriptor = socket(AF_INET, SOCK_STREAM, 0);

		/* Direccion Local */
		struct sockaddr_in *local_address = malloc(sizeof(struct sockaddr_in));
		/* Direccion remota ( a la que me quiero conectar )*/
		struct sockaddr_in *remote_address = malloc(sizeof(struct sockaddr_in));
		/* Direccion remota ( a la que me quiero conectar )*/
		struct sockaddr_in *remote_addressPDD = malloc(sizeof(struct sockaddr_in));

		{       /* Con esto fuerzo a que el puerto local sea el 5201 y que tome la IP por defecto de la PC */
			local_address->sin_family = AF_INET;
			local_address->sin_addr.s_addr = INADDR_ANY;
			local_address->sin_port = htons(PuertoPFS);

			bind(descriptor, (struct sockaddr *)local_address, sizeof(struct sockaddr_in));
		}

		{       /* Con esto indico que me quiero conectar al puerto 9034 de la IP 127.0.0.1 (localhost)-->RAID */
			remote_address->sin_family = AF_INET;
			remote_address->sin_addr.s_addr = inet_addr(direccionIPRaid);
			remote_address->sin_port = htons(PuertoDelRaid);
		}

		{       /* Con esto indico que me quiero conectar al puerto 9048 de la IP 127.0.0.1 (localhost) -> PDD*/
			remote_addressPDD->sin_family = AF_INET;
			remote_addressPDD->sin_addr.s_addr = inet_addr(direccionIPPDD);
			remote_addressPDD->sin_port = htons(PuertoPDD);
		}

		/* Me conecto al servidor */
		if(connect(descriptor, (struct sockaddr *)remote_address , sizeof(struct sockaddr_in))==-1){
			//perror("connect");
			puts("No se pudo conectar al RAID");
			if(connect(descriptor, (struct sockaddr *)remote_addressPDD, sizeof(struct sockaddr_in))==-1){
				perror("connect");
				puts("No se pudo conectar al PDD");
			};
		};

		paqueteP->num_msg = 0;
		paqueteP->longitud = 0;

		if(send(descriptor, paqueteP, sizeof(paqueteNIPC), 0)==-1){
			perror("send");
			puts("Falló el envío del paquete para HS");
		};

		if(recv(descriptor, &paquete, sizeof(paqueteNIPC), 0)==-1){
			perror("recv");
			puts("No se pudo recibir la respuesta del intento de Handshake");
		};

		if((paquete.num_msg==0)&&(paquete.longitud==0)){
			puts("Handshake exitoso");

			//puts("Acá empieza");
	//---------------------------------------- Aca va el main del pfs--------------------------------------
		//	sector = 0;

			//Leer un cluster desde ese sector

			for(n=0;n<8;n++){
				paqueteP->num_msg = 3;
				paqueteP->longitud = sizeof(uint32_t) + sizeof(payloadEscritura.contenido);

				payloadEscritura.sector = primerSector;
				memcpy(&payloadEscritura.contenido,contCluster+(512*n),512);

				memcpy(&paqueteP->payload,&payloadEscritura,sizeof(payloadEscritura));

				if(send(descriptor,paqueteP,sizeof(paqueteNIPC),0)==-1){
					perror("send");
				};
				cluster[n].numSector = primerSector;
				primerSector++;
			};

			for(n=0;n<8;n++){

				if(recv(descriptor,&paquete,sizeof(paqueteNIPC),0)==-1){
							perror("recv");
				};

				if(paquete.num_msg == 4){

				memcpy(&payloadEscritura, paquete.payload, sizeof(payloadEscritura));

				m = 0;

				while(cluster[m].numSector!=payloadEscritura.sector){
					m++;
				};

				memcpy(&cluster[m].contenido,payloadEscritura.contenido,sizeof(payloadEscritura.contenido));

				};

			};


	//-------------------------------------------------------------------------------------------------------


		} else {
			if(paquete.num_msg==-1){
				printf("%s\n",paquete.payload);
			};
			puts("Handshake falló");
		};


		/* Cierro el socket y por ende la conexion */
		free(paqueteP);
		close(descriptor);

		free(local_address);
		free(remote_address);
		free(remote_addressPDD);
		usleep(100000);
	}

